import BaseXform from '../base-xform';
import colCache from '../../../utils/col-cache';

class DefinedNamesXform extends BaseXform {
    render(xmlStream, model) {
        // <definedNames>
        //   <definedName name="name">name.ranges.join(',')</definedName>
        //   <definedName name="_xlnm.Print_Area" localSheetId="0">name.ranges.join(',')</definedName>
        // </definedNames>
        xmlStream.openNode('definedName', {
            name: model.name,
            localSheetId: model.localSheetId,
        });
        xmlStream.writeText(model.ranges.join(','));
        xmlStream.closeNode();
    }

    parseXmlObject(node) {
        let hasValue = false;
        if (node._name === 'definedName') {
            this._parsedName = node._attributes.name;
            this._parsedLocalSheetId = node._attributes.localSheetId;
            this._parsedText = node._text || "";
            this.model = {
                name: this._parsedName,
                ranges: extractRanges(this._parsedText),
            };
            if (this._parsedLocalSheetId !== undefined) {
                this.model.localSheetId = parseInt(this._parsedLocalSheetId, 10);
            }
            hasValue = true;
        }
        return hasValue;
    }

    parseOpen(node) {
        switch (node.name) {
            case 'definedName':
                this._parsedName = node.attributes.name;
                this._parsedLocalSheetId = node.attributes.localSheetId;
                this._parsedText = [];
                return true;
            default:
                return false;
        }
    }

    parseText(text) {
        this._parsedText.push(text);
    }

    parseClose() {
        this.model = {
            name: this._parsedName,
            ranges: extractRanges(this._parsedText.join('')),
        };
        if (this._parsedLocalSheetId !== undefined) {
            this.model.localSheetId = parseInt(this._parsedLocalSheetId, 10);
        }
        return false;
    }
}

function isValidRange(range) {
    try {
        colCache.decodeEx(range);
        return true;
    } catch (err) {
        return false;
    }
}

function extractRanges(parsedText) {
    const ranges = [];
    let quotesOpened = false;
    let last = '';
    parsedText.split(',').forEach(item => {
        if (!item) {
            return;
        }
        const quotes = (item.match(/'/g) || []).length;

        if (!quotes) {
            if (quotesOpened) {
                last += `${item},`;
            } else if (isValidRange(item)) {
                ranges.push(item);
            }
            return;
        }
        const quotesEven = quotes % 2 === 0;

        if (!quotesOpened && quotesEven && isValidRange(item)) {
            ranges.push(item);
        } else if (quotesOpened && !quotesEven) {
            quotesOpened = false;
            if (isValidRange(last + item)) {
                ranges.push(last + item);
            }
            last = '';
        } else {
            quotesOpened = true;
            last += `${item},`;
        }
    });
    return ranges;
}

export default DefinedNamesXform;
